package com.ap.core.validation.service.impl;

import com.ap.core.business.info.ValidationInfo;
import com.ap.core.common.types.ValidationType;
import com.ap.core.validation.info.ValidationResult;
import com.ap.core.validation.rules.ValidationRule;
import com.ap.core.validation.service.BusinessValidationService;
import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Implementation class for {@link BusinessValidationService}
 */
public class DefaultBusinessValidationService implements BusinessValidationService<Object> {

    private final static Logger LOG = LoggerFactory.getLogger(DefaultBusinessValidationService.class);

    /**
     * The rule map containing mapping of validation type and validation rules applicable for that validation type.
     */	
    private final Map<ValidationType, List<ValidationRule<Object>>> ruleMap;

    /** Whether rule validation should stop if any rule fails. */
    private final boolean failFast;

    /**
     * Instantiates a new default business validation service.
     * 
     * @param ruleMap
     *            the rule map
     * @param failFast
     *            the fail fast
     */
    public DefaultBusinessValidationService(Map<ValidationType, List<ValidationRule<Object>>> ruleMap, boolean failFast) {
        this.ruleMap = ruleMap;
        this.failFast = failFast;
    }

    @Override
    public ValidationResult validate(Object object, ValidationType validationType) {
        // executes rules on the domain object and returns list of failures
        boolean passed = true;

        // get rule list to be applied to the object.
        final List<ValidationRule<Object>> rules = ruleMap.get(validationType);
        final List<ValidationInfo> failedRuInfo = new ArrayList<ValidationInfo>();
        if (null != rules) {

            for (ValidationRule<Object> rule : rules) {

                // call business rule here
                passed = rule.validate(object);

                if(!passed){
                    LOG.info("\nFailed Business Rule during the ValidationType:"+validationType 
                    		 + " With the Internal Error Code:"+ rule.getErrorCode() + " at time : " + new LocalDateTime());
                    failedRuInfo.add(new ValidationInfo(rule.getErrorCode()));
                    rule.onFailureAction(object);
                }

                /*
                 * If fail fast is set return immediately on encountering an error
                 */
                if ((failFast && !passed)) {
                    break;
                }
            }
        }
        return new ValidationResult(failedRuInfo);

    }

}
